home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-1.iso / games / ted5.zip / IGRABSRC.ZIP / JHUFF.C < prev    next >
C/C++ Source or Header  |  1993-02-04  |  8KB  |  431 lines

  1. /**************************************************************
  2.     JHUFF.C -- A rle/huffman Data Compression Program
  3. **************************************************************/
  4.  
  5. #include "igrab.h"
  6. #pragma hdrstop
  7.  
  8. unsigned char huge *infile,
  9.           huge *outfile;
  10.  
  11. long inlength,outlength;
  12.  
  13. long counts[256];
  14.  
  15. unsigned huffbits[256];
  16. unsigned long huffstring[256];
  17.  
  18. huffnode nodearray[256];    // 256 nodes is worst case
  19.  
  20. /*
  21. =============================================================================
  22.  
  23.                COMPRESSION SUBS
  24.  
  25. =============================================================================
  26. */
  27.  
  28.  
  29.  
  30. /*
  31. ======================
  32. =
  33. = CountBytes
  34. =
  35. = Adds the bytes in the pointed to area to the counts array
  36. = If this is the first segment, make sure counts is zerod
  37. =
  38. ======================
  39. */
  40.  
  41. void CountBytes (unsigned char huge *start, long length)
  42. {
  43.   long i;
  44.  
  45.   while (length--)
  46.     counts[*start++]++;
  47. }
  48.  
  49. /*
  50. =======================
  51. =
  52. = FindLeast
  53. =
  54. = Returns the byte with the lowest counts value
  55. =
  56. =======================
  57. */
  58.  
  59. int FindLeast (void)
  60. {
  61.   int i,least;
  62.   long low = 0x7fffffff;
  63.  
  64.   for (i=0;i<256;i++)
  65.     if (counts[i]<low)
  66.     {
  67.       low = counts[i];
  68.       least = i;
  69.     }
  70.  
  71.   return least;
  72. }
  73.  
  74. /*========================================================================*/
  75.  
  76. /*
  77. ==================
  78. =
  79. = TraceNode
  80. =
  81. = A recursive function that follows all leaves of nodearray and fills in
  82. = coding tables huffbits and huffstring.
  83. =
  84. ==================
  85. */
  86.  
  87. void TraceNode (int nodenum,int numbits,unsigned long bitstring)
  88. {
  89.   unsigned bit0,bit1;
  90.  
  91.   bit0 = nodearray[nodenum].bit0;
  92.   bit1 = nodearray[nodenum].bit1;
  93.  
  94.   numbits++;
  95.  
  96.  
  97.   if (bit0 <256)
  98.   {
  99.     huffbits[bit0]=numbits;
  100.     huffstring[bit0]=bitstring;        // just added a zero in front
  101.   }
  102.   else
  103.   {
  104.     if (numbits<24)            // if the string is this long, its 0
  105.       TraceNode (bit0-256,numbits,bitstring);
  106.   }
  107.  
  108.   if (bit1 <256)
  109.   {
  110.     huffbits[bit1]=numbits;
  111.     huffstring[bit1]=bitstring+ (1ul<<(numbits-1));    // add a one in front
  112.     if (huffbits[bit1]>24 && counts[bit1])
  113.     {
  114.       puts("Error: Huffman bit string went over 32 bits!");
  115.       exit(1);
  116.     }
  117.   }
  118.   else
  119.   {
  120.     if (numbits<24)            // if the string is this long, its 0
  121.      TraceNode (bit1-256,numbits,bitstring+(1ul<<(numbits-1)));
  122.   }
  123. }
  124.  
  125.  
  126. /*
  127. =======================
  128. =
  129. = Huffmanize
  130. =
  131. = Takes the counts array and builds a huffman tree at
  132. = nodearray, then builds a codeing table.
  133. =======================
  134. */
  135.  
  136. void Huffmanize (void)
  137. {
  138. //
  139. // codes are either bytes if <256 or nodearray numbers+256 if >=256
  140. //
  141.   unsigned value[256],code0,code1;
  142. //
  143. // probablilities are the number of times the code is hit or $ffffffff if
  144. // it is allready part of a higher node
  145. //
  146.   unsigned long prob[256],low,workprob;
  147.  
  148.   int i,worknode,bitlength;
  149.   unsigned long bitstring;
  150.  
  151.   memset(huffstring,0,sizeof(huffstring));
  152.   memset(huffbits,0,sizeof(huffbits));
  153.  
  154. //
  155. // all possible leaves start out as bytes
  156. //
  157.   for (i=0;i<256;i++)
  158.   {
  159.     value[i]=i;
  160.     prob[i]=counts[i];
  161.   }
  162.  
  163. //
  164. // start selecting the lowest probable leaves for the ends of the tree
  165. //
  166.  
  167.   worknode = 0;
  168.   while (1)    // break out of when all codes have been used
  169.   {
  170.     //
  171.     // find the two lowest probability codes
  172.     //
  173.  
  174.     code0=0xffff;
  175.     low = 0x7ffffffff;
  176.     for (i=0;i<256;i++)
  177.       if (prob[i]<low)
  178.       {
  179.     code0 = i;
  180.     low = prob[i];
  181.       }
  182.  
  183.     code1=0xffff;
  184.     low = 0x7fffffff;
  185.     for (i=0;i<256;i++)
  186.       if (prob[i]<low && i != code0)
  187.       {
  188.     code1 = i;
  189.     low = prob[i];
  190.       }
  191.  
  192.     if (code1 == 0xffff)
  193.     {
  194.       if (value[code0]<256)
  195.     errout("Weirdo huffman error: last code wasn't a node!");
  196.       if (value[code0]-256 != 254)
  197.     errout("Weirdo huffman error: headnode wasn't 254!");
  198.       break;
  199.     }
  200.  
  201.     //
  202.     // make code0 into a pointer to work
  203.     // remove code1 (make 0xffffffff prob)
  204.     //
  205.     nodearray[worknode].bit0 = value[code0];
  206.     nodearray[worknode].bit1 = value[code1];
  207.  
  208.     value[code0] = 256 + worknode;
  209.     prob[code0] += prob[code1];
  210.     prob[code1] = 0xffffffff;
  211.     worknode++;
  212.   }
  213.  
  214. //
  215. // done with tree, now build table recursively
  216. //
  217.  
  218.   TraceNode (254,0,0);
  219.  
  220. }
  221.  
  222. /*========================================================================*/
  223.  
  224. /*
  225. ===============
  226. =
  227. = OptimizeNodes
  228. =
  229. = Goes through a huffman table and changes the 256-511 node numbers to the
  230. = actular address of the node.  Must be called before HuffExpand
  231. =
  232. ===============
  233. */
  234.  
  235. void OptimizeNodes (huffnode *table)
  236. {
  237.   huffnode *node;
  238.   int i;
  239.  
  240.   node = table;
  241.  
  242.   for (i=0;i<255;i++)
  243.   {
  244.     if (node->bit0 >= 256)
  245.       node->bit0 = (unsigned)(table+(node->bit0-256));
  246.     if (node->bit1 >= 256)
  247.       node->bit1 = (unsigned)(table+(node->bit1-256));
  248.     node++;
  249.   }
  250. }
  251.  
  252. /*========================================================================*/
  253.  
  254. /*
  255. ======================
  256. =
  257. = HuffCompress
  258. =
  259. = The file must be counted with CountBytes and then Huffmanized first
  260. =
  261. ======================
  262. */
  263.  
  264. long HuffCompress (unsigned char huge *source, long length,
  265.   unsigned char huge *dest)
  266. {
  267.   long outlength;
  268.   unsigned long string;
  269.   unsigned biton,bits;
  270.   unsigned char byte;
  271.  
  272.  
  273.   if (length<60000)
  274.   {
  275.     FastHuffCompress(source,length,dest);
  276.     return;
  277.   }
  278.  
  279.   outlength = biton = 0;
  280.  
  281.   *(long huge *)dest=0;        // so bits can be or'd on
  282.  
  283.   while (length--)
  284.   {
  285.     byte = *source++;
  286.     bits = huffbits[byte];
  287.     string = huffstring[byte] << biton;
  288.     *(long huge *)(dest+1)=0;    // so bits can be or'd on
  289.     *(long huge *)dest |= string;
  290.     biton += bits;        // advance this many bits
  291.     dest+= biton/8;
  292.     biton&=7;            // stay under 8 shifts
  293.     outlength+=bits;
  294.   }
  295.  
  296.   return (outlength+7)/8;
  297. }
  298.  
  299. /*========================================================================*/
  300.  
  301. /*
  302. ======================
  303. =
  304. = HuffExpand
  305. =
  306. ======================
  307. */
  308.  
  309. void HuffExpand (unsigned char huge *source, unsigned char huge *dest,
  310.   long length,huffnode *hufftable)
  311. {
  312.   unsigned bit,byte,node,code;
  313.   unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;
  314.   huffnode *nodeon,*headptr;
  315.  
  316.   nodeon = headptr = hufftable+254;    // head node is allways node 254
  317.  
  318.   bit = 1;
  319.   byte = *source++;
  320.  
  321.   while (length)
  322.   {
  323.     if (byte&bit)
  324.       code = nodeon->bit1;
  325.     else
  326.       code = nodeon->bit0;
  327.  
  328.     bit<<=1;
  329.     if (bit==256)
  330.     {
  331.       bit=1;
  332.       byte = *source++;
  333.     }
  334.  
  335.     if (code<256)
  336.     {
  337.       *dest++=code;
  338.       nodeon=headptr;
  339.       length--;
  340.     }
  341.     else
  342.       nodeon = (huffnode *)code;
  343.   }
  344.  
  345.  
  346. #if 0
  347.  
  348.   source++;    // normalize
  349.   source--;
  350.   dest++;
  351.   dest--;
  352.  
  353.   sourceseg = FP_SEG(source);
  354.   sourceoff = FP_OFF(source);
  355.   destseg = FP_SEG(dest);
  356.   destoff = FP_OFF(dest);
  357.  
  358.   length--;
  359. //
  360. // al = source byte
  361. // cl = bit in source (1,2,4,8,...)
  362. // dx = code
  363. //
  364. // ds:si source
  365. // es:di dest
  366. // ss:bx node pointer
  367. //
  368.  
  369. asm     mov    bx,headptr
  370. asm    mov    cl,1
  371.  
  372. asm    mov    si,sourceoff
  373. asm    mov    di,destoff
  374. asm    mov    es,destseg
  375. asm    mov    ds,sourceseg
  376.  
  377. asm    lodsb            // load first byte
  378.  
  379. expand:
  380. asm    test    al,cl        // bit set?
  381. asm    jnz    bit1
  382. asm    mov    dx,ss:bx    // take bit0 path from node
  383. asm    jmp    gotcode
  384. bit1:
  385. asm    mov    dx,ss:bx+2    // take bit1 path
  386.  
  387. gotcode:
  388. asm    shl    cl,1        // advance to next bit position
  389. asm    jnc    sourceup
  390. asm    lodsb
  391. asm    cmp    si,0x10        // normalize ds:si
  392. asm      jb    sinorm
  393. asm    mov    cx,ds
  394. asm    inc    cx
  395. asm    mov    ds,cx
  396. asm    xor    si,si
  397. sinorm:
  398. asm    mov    cl,1        // back to first bit
  399.  
  400. sourceup:
  401. asm    or    dh,dh        // if dx<256 its a byte, else move node
  402. asm    jz    storebyte
  403. asm    mov    bx,dx        // next node = (huffnode *)code
  404. asm    jmp    expand
  405.  
  406. storebyte:
  407. asm    mov    [es:di],dl
  408. asm    inc    di        // write a decopmpressed byte out
  409. asm    mov    bx,headptr    // back to the head node for next bit
  410.  
  411. asm    cmp    di,0x10        // normalize es:di
  412. asm      jb    dinorm
  413. asm    mov    dx,es
  414. asm    inc    dx
  415. asm    mov    es,dx
  416. asm    xor    di,di
  417. dinorm:
  418.  
  419. asm    sub    WORD PTR ss:length,1
  420. asm    jnc    expand
  421. asm      dec    WORD PTR ss:length+2
  422. asm    jns    expand        // when length = ffff ffff, done
  423.  
  424. asm    mov    ax,ss
  425. asm    mov    ds,ax
  426.  
  427. #endif
  428.  
  429. }
  430.